package jvm;

import java.util.concurrent.atomic.AtomicInteger;

/*
JMM java内存模型的可见性的验证
 */
class MyDdata {
    //线程之间的通知机制，volatile能够保证内存可见性，
    /*
    一、原子性是指的是什么意思？
        不可分割，完整性，即某个线程正在做某个业务时，中间不可以被加塞或者被分割。
        需要整体完整，要么同时成功，要么同时失败。保证数据的完整性和一致性。


    二、volatile关键字的作用
    1、保证内存可见性：可见性是指线程之间的可见性，一个线程修改的状态对另一个线程是可见的。
    2、禁止指令重排：指令重排序是JVM为了优化指令、提高程序运行效率。
        volatile禁止指令重排优化，从而避免多线程环境下程序出现乱序执行的现象。
        实现禁止指令排序的是怎么实现的？
        内存屏障（Memory Barrier) 内存栅栏，是一个CPU指令。作用有两个
        1、保证特定操作的执行顺序。
        2、保证某些变量的内存可见性（利用该特性实现volatile的内存可见性）。
        由于编译器和处理器都能够对指令进行重排优化。如何在指令间插入一条Memory Barrier
        则会告诉编译器和CPU，不管什么指令都不能和这条Memory Barrier指令重排序。
        即通过插入内存屏障禁止在内存屏障前后的指令执行重排优化。
        内存屏障的另外一个作用是强制刷出各种CPU的缓存数据，因此任何CPU
        上的线程都能够读取到这些数据的最新版本。

        对volatile变量进行写操作时候，会在写操作后添加一条store屏障指令，
        将工作内存中共享变量的值重新刷新回到主内存。

        对volatile变量进行读操作时候，会在读操作之前加入一条load屏障指令，
        从主内存中读取共享变量的
    3、不保证原子性

    三、volatile为什么不能保证原子性？
        出现了丢失写值的情况。
        使用JUC 下的原子包 原子整型类
     */
    volatile int number = 10;

    public void addTo12306() {
        this.number = 12306;
    }
    //此时number前面是加了volatile关键字修饰的，volatile不保证原子性
    public /*synchronized*/ void adPlusPlus() {
        number++;
    }


    AtomicInteger atomicInteger = new AtomicInteger();
    public void addAtomic() {
        atomicInteger.getAndIncrement();
    }
}

public class Test08 {
    public static void main(String[] args) {
        MyDdata myDdata = new MyDdata();


        for(int i = 1; i <=20; i++) {
            new Thread(() -> {
            //线程执行方法语句
                for (int j = 1; j <= 1000 ; j++) {
                    myDdata.adPlusPlus();
                    myDdata.addAtomic();
                }
            },String.valueOf(i)).start();
          }
        //需要等待上面20个线程全部完成后，再用main线程去读取最终的结果。
        //判断上述线程是否都执行完毕了
        while (Thread.activeCount() > 2) {
            //礼让线程，让出cpu
            Thread.yield();
        }

        System.out.println(Thread.currentThread().getName() + "\t int type finally number value :" + myDdata.number);
        System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type finally number value :" + myDdata.atomicInteger);
    }
    //volatile可以保证可见性，及时通知其他线程，主物理内存的值已经修改。
    public static void seeOKByVolatile() {
        MyDdata myDdata = new MyDdata();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "  **************Come in******");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myDdata.addTo12306();
            System.out.println(Thread.currentThread().getName() + " number value : " + myDdata.number);
        },"AAAAA").start();

        while (myDdata.number == 10) {

        }

        System.out.println(Thread.currentThread().getName() + "\t number value :" + myDdata.number);
    }
}
